home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000 #2
/
Ham Radio 2000 - Volume 2.iso
/
HAMV2
/
TCP_IP
/
TNOS230S
/
FTPCLI.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-08-18
|
48KB
|
1,916 lines
/* Internet FTP client (interactive user)
* Copyright 1991 Phil Karn, KA9Q
*/
/* Mods by G1EMM and PA0GRI */
/* modifications for encrypted password by ik1che 900419 */
/* added "resume" and "rput" commands for interrupted file transfers
* by iw0cnb 15 Feb 92 */
/* VIEW command added by Simon G1FHY. Mod by Paul@wolf.demon.co.uk */
#include "global.h"
#include "commands.h"
#include "files.h"
#ifdef UNIX
#include <sys/stat.h>
#endif
#include "mbuf.h"
#include "session.h"
#ifdef MSDOS
#include "ctype.h"
#else
#include "socket.h"
#endif
#include "netuser.h"
#ifdef LZW
#include "lzw.h"
#endif
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: ftpcli.c,v 1.28 1997/08/19 01:19:22 root Exp root $";
#endif
#define FTPDIRBUF 256
#ifdef ALLSESSIONS
static int compsub (struct ftpcli * ftp, char *localname, char *remotename);
static int txlate (int argc, char *argv[], void *p, const char *substr, int parm);
static int doascii (int argc, char *argv[], void *p);
static int dobatch (int argc, char *argv[], void *p);
static int dobinary (int argc, char *argv[], void *p);
static int docompare (int argc, char *argv[], void *p);
static int doftpcd (int argc, char *argv[], void *p);
static int doftpcdup (int argc, char *argv[], void *p);
static int doftpdel (int argc, char *argv[], void *p);
static int doget (int argc, char *argv[], void *p);
static int dohash (int argc, char *argv[], void *p);
static int doverbose (int argc, char *argv[], void *p);
static int dolist (int argc, char *argv[], void *p);
static int dols (int argc, char *argv[], void *p);
static int domd5 (int argc, char *argv[], void *p);
#ifdef ALLSESSIONS
static int doldir (int argc, char *argv[], void *p);
#endif
static int dolcd (int argc, char *argv[], void *p);
static int dolmkdir (int argc, char *argv[], void *p);
static int dolrename (int argc, char *argv[], void *p);
static int dolrmdir (int argc, char *argv[], void *p);
#ifdef LZW
static int doftplzw (int argc, char *argv[], void *p);
#endif
static int domcompare (int argc, char *argv[], void *p);
static int domkdir (int argc, char *argv[], void *p);
static int domget (int argc, char *argv[], void *p);
static int domput (int argc, char *argv[], void *p);
static int doput (int argc, char *argv[], void *p);
static int dopwd (int argc, char *argv[], void *p);
static int doftphelp (int argc, char *argv[], void *p);
static int doquit (int argc, char *argv[], void *p);
static int dormdir (int argc, char *argv[], void *p);
static int doftprename (int argc, char *argv[], void *p);
static int doresume (int argc, char *argv[], void *p);
static int dorput (int argc, char *argv[], void *p);
static int dotype (int argc, char *argv[], void *p);
static int doftpview (int argc, char *argv[], void *p);
static int ftpgetline (struct session * sp, const char *prompt, char *buf, int n);
static int getresp (struct ftpcli * ftp, int mincode);
static int doftpupdate (int argc, char *argv[], void *p);
static long getsub (struct ftpcli * ftp, const char *command, const char *remotename,
char *localname);
static long putsub (struct ftpcli * ftp, char *remotename, char *localname, int putr);
static void sendport (int s, struct sockaddr_in * thesocket);
static char *ftpcli_login (struct ftpcli * ftp, char *host);
#ifdef LZW
static int synclzw (register struct ftpcli * ftp);
#endif
#ifdef MSDOS
extern void strrev (char *str);
#endif
static char Notsess[] = "Not an FTP session!\n";
static int Ftp_type = ASCII_TYPE;
static int Ftp_logbsize = 8;
static struct cmds Ftpcmds[] =
{
{ "", donothing, 0, 0, NULLCHAR },
{ "?", doftphelp, 0, 0, NULLCHAR },
{ "append", doput, 0, 2, "append <localfile> <remotefile>" },
{ "ascii", doascii, 0, 0, NULLCHAR },
{ "batch", dobatch, 0, 0, NULLCHAR },
{ "binary", dobinary, 0, 0, NULLCHAR },
{ "bye", doquit, 0, 0, NULLCHAR },
{ "cd", doftpcd, 0, 2, "cd <directory>" },
{ "cdup", doftpcdup, 0, 0, NULLCHAR },
{ "compare", docompare, 0, 2, "compare <remotefile> [<localfile>]" },
{ "del", doftpdel, 0, 2, "del <remotefile>" },
{ "dir", dolist, 0, 0, NULLCHAR },
{ "exit", doquit, 0, 0, NULLCHAR },
{ "get", doget, 0, 2, "get <remotefile> <localfile>" },
{ "hash", dohash, 0, 0, NULLCHAR },
{ "help", doftphelp, 0, 0, NULLCHAR },
{ "lcd", dolcd, 0, 1, NULLCHAR },
#ifdef ALLSESSIONS
{ "ldir", doldir, 0, 1, NULLCHAR },
#endif
{ "list", dolist, 0, 0, NULLCHAR },
{ "lmkdir", dolmkdir, 0, 2, "lmkdir <local Directory>" },
{ "lrename", dolrename, 0, 3, "lrename <oldname> <newname>" },
{ "lrmdir", dolrmdir, 0, 2, "lrmdir <local Directory>" },
{ "ls", dols, 0, 0, NULLCHAR },
#ifdef LZW
{ "lzw", doftplzw, 0, 0, NULLCHAR },
#endif
{ "mcompare", domcompare, 0, 2, "mcompare <file> [<file> ...]" },
{ "md", domkdir, 0, 2, "md <directory>" },
{ "md5", domd5, 0, 2, "md5 <file>" },
{ "mget", domget, 0, 2, "mget <file> [<file> ...]" },
{ "mkdir", domkdir, 0, 2, "mkdir <directory>" },
{ "mput", domput, 0, 2, "mput <file> [<file> ...]" },
{ "nlist", dols, 0, 0, NULLCHAR },
{ "nlst", dols, 0, 0, NULLCHAR },
{ "put", doput, 0, 2, "put <localfile> <remotefile>" },
{ "pwd", dopwd, 0, 0, NULLCHAR },
{ "quit", doquit, 0, 0, NULLCHAR },
{ "rename", doftprename, 0, 3, "rename <oldname> <newname>" },
{ "resume", doresume, 0, 2, "resume <remotefile> <localfile>" },
{ "rmdir", dormdir, 0, 2, "rmdir <directory>" },
{ "rput", dorput, 0, 2, "rput <localfile> <remotefile>" },
{ "type", dotype, 0, 0, NULLCHAR },
{ "update", doftpupdate, 0, 0, NULLCHAR },
{ "verbose", doverbose, 0, 0, NULLCHAR },
{ "view", doftpview, 0, 2, "view <remotefile>"},
{ NULLCHAR, NULLFP ((int, char **, void *)),
0, 0, NULLCHAR }
};
int
doftphelp (int argc, char *argv[], void *p OPTIONAL)
{
dohelper ("FTP commands:\n", &Ftpcmds[1], NULLCHAR, (argv[0][0] == '?' && argc == 1) ? NULLCHAR : FTPHelp, (argc == 2) ? argv[1] : NULLCHAR);
return 0;
}
/* Handle top-level FTP command */
int
doftp (int argc, char *argv[], void *p OPTIONAL)
{
struct session *sp;
struct ftpcli ftp;
struct sockaddr_in fsocket;
int resp, vsave;
char *buf, *bufsav, *un;
char const *cp;
char prmt[40];
#ifdef notyet
char l[17];
#endif
int control;
static FILE *fp1 = NULLFILE;
struct cur_dirs dirs;
int pauseonexit = 0;
/*Make sure this comes from console - WG7J*/
if (Curproc->input != Command->input)
return 0;
/* Allocate a session control block */
if ((sp = newsession (argv[1], FTP, 0)) == NULLSESSION) {
tputs (TooManySessions);
return 1;
}
memset ((char *) &ftp, 0, sizeof (ftp));
ftp.control = ftp.data = -1;
ftp.verbose = V_BYTE; /* changed to ver 4 default - KO4KS */
ftp.type = (char) Ftp_type;
ftp.logbsize = Ftp_logbsize;
sp->cb.ftp = &ftp; /* Downward link */
ftp.session = sp; /* Upward link */
ftp.curdirs = &dirs;
fsocket.sin_family = AF_INET;
fsocket.sin_port = IPPORT_FTP;
tprintf ("Resolving %s... ", sp->name);
if ((fsocket.sin_addr.s_addr = resolve (sp->name)) == 0) {
tprintf (Badhost, sp->name);
(void) keywait (NULLCHAR, 1);
freesession (sp);
return 1;
}
/* Open the control connection */
if ((control = sp->s = ftp.control = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
tputs (Nosock);
(void) keywait (NULLCHAR, 1);
freesession (sp);
return 1;
}
(void) sockmode (sp->s, SOCK_ASCII);
(void) setflush (sp->s, -1); /* Flush output only when we call getresp() */
tprintf ("Trying %s...\n", psocket ((struct sockaddr *) &fsocket));
tprintf ("Local Directory - %s\n", init_dirs (&dirs));
if (connect (control, (char *) &fsocket, sizeof (fsocket)) == -1)
goto quit;
tprintf ("FTP session %u connected to %s\n", (unsigned) (sp - Sessions),
sp->name);
/* Wait for greeting from server */
resp = getresp (&ftp, 200);
if (resp >= 400)
goto quit;
if ((un = getenv ("LOGNAME")) == NULLCHAR)
un = getenv ("USER");
if (un != NULLCHAR)
sprintf (prmt, "Enter user name (%s): ", un);
else
sprintf (prmt, "Enter user name: ");
/* Now process responses and commands */
buf = mallocw (LINELEN);
/*lint -esym(668, fp1) */
if (argc > 2) {
if ((fp1 = fopen (argv[2], READ_TEXT)) == NULLFILE)
goto quit1;
if (argc > 3 && tolower (argv[3][0]) == 'p')
pauseonexit = 1;
} else
pauseonexit = 1;
while (resp != -1) {
switch (resp) {
case 220: /* Sign-on banner; prompt for and send USER command */
if ((cp = ftpcli_login (&ftp, sp->name)) == NULLCHAR) {
if (argc > 2) {
if (fgets (buf, LINELEN, fp1) == NULLCHAR)
goto quit1;
} else if (ftpgetline (sp, prmt, buf, LINELEN) == -1) {
resp = -1;
continue;
}
/* Send the command only if the user response
* was non-null
*/
if (buf[0] != '\n') {
usprintf (control, "USER %s", buf);
resp = getresp (&ftp, 200);
} else {
if (un != NULLCHAR) {
usprintf (control, "USER %s\n", un);
resp = getresp (&ftp, 200);
} else {
tputs ("No username sent\n");
resp = 200; /* dummy */
}
}
} else {
usprintf (control, "USER %s\n", cp);
free (cp);
resp = getresp (&ftp, 200);
}
break;
case 331:
if (ftp.password == NULLCHAR) {
/* turn off echo */
if (argc > 2) {
if (fgets (buf, LINELEN, fp1) == NULLCHAR)
goto quit1;
} else {
sp->ttystate.echo = 0;
if (ftpgetline (sp, "Password: ", buf, LINELEN) == -1) {
resp = -1;
continue;
}
tputc ('\n');
/* Turn echo back on */
sp->ttystate.echo = 1;
}
/* Send the command only if the user response
* was non-null
*/
if (buf[0] != '\n') {
usprintf (control, "PASS %s", buf);
resp = getresp (&ftp, 200);
} else {
tputs ("Password must be provided.\nLogin failed.\n");
resp = 200; /* dummy */
}
} else {
usprintf (control, "PASS %s\n", ftp.password);
resp = getresp (&ftp, 200);
free (ftp.password);
ftp.password = NULLCHAR; /* clean up */
}
break;
case 230: /* Successful login */
/* Find out what type of system we're talking to */
tputs ("ftp> syst\n");
usprintf (control, "SYST\n");
resp = getresp (&ftp, 200);
break;
case 215: /* Response to SYST command */
cp = strchr (ftp.line, ' ');
if (cp != NULLCHAR && strnicmp (cp + 1, System, strlen (System)) == 0) {
ftp.type = IMAGE_TYPE;
tputs ("Defaulting to binary mode\n");
}
resp = 200; /* dummy */
break;
#ifdef notyet
case 399: /* Encrypted password login */
if (ftp.password == NULLCHAR) {
if (ftpgetline (sp, "Key ? --> ", buf, LINELEN) == -1) {
resp = -1;
continue;
}
/* Send the command only if the user response
* was non-null
*/
if (buf[0] != '\n') {
cp = strchr (ftp.line, ':');
cp += 2;
/*
epass(htol(cp),buf,l);
*/
l[16] = '\0';
free (ftp.line);
ftp.line = NULLCHAR;
usprintf (control, "PASS %s\n", l);
resp = getresp (&ftp, 200);
} else {
tputs ("Password must be provided.\nLogin failed.\n");
resp = 200; /* dummy */
}
} else {
cp = strchr (ftp.line, ':');
cp += 2;
/*
epass(htol(cp),ftp.password,l);
*/
l[16] = '\0';
free (ftp.line);
ftp.line = NULLCHAR;
usprintf (control, "PASS %s\n", l);
resp = getresp (&ftp, 200);
free (ftp.password);
ftp.password = NULLCHAR; /* clean up */
}
break;
#endif
default: /* Test the control channel first */
if (sockstate (control) == NULLCHAR) {
resp = -1;
break;
}
if (argc > 2) {
if (fgets (buf, LINELEN, fp1) == NULLCHAR)
goto quit1;
} else if (ftpgetline (sp, "ftp> ", buf, LINELEN) == -1) {
resp = -1;
continue;
}
/* Copy because cmdparse modifies the original */
bufsav = strdup (buf);
if ((resp = cmdparse (Ftpcmds, buf, &ftp)) != -1) {
/* Valid command, free buffer and get another */
free (bufsav);
} else {
/* Not a local cmd, send to remote server */
usputs (control, bufsav);
free (bufsav);
/* Enable display of server response */
vsave = ftp.verbose;
ftp.verbose = V_NORMAL;
resp = getresp (&ftp, 200);
ftp.verbose = (int16) vsave;
}
}
}
quit1: free (buf);
quit: cp = sockerr (control);
tprintf ("FTP session %u closed: %s\n", (unsigned) (sp - Sessions),
cp != NULLCHAR ? cp : "EOF");
if (ftp.fp != NULLFILE && ftp.fp != stdout)
(void) fclose (ftp.fp);
if (ftp.data != -1)
close_s (ftp.data);
if (ftp.control != -1)
close_s (ftp.control);
if (pauseonexit)
(void) keywait (NULLCHAR, 1);
if (fp1 != NULLFILE)
(void) fclose (fp1);
if (ftp.session != NULLSESSION)
freesession (ftp.session);
free_dirs (&dirs);
return 0;
}
/* Control verbosity level */
static int
doverbose (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
if ((ftp = (struct ftpcli *) p) == NULLFTP)
return -1;
return setshort (&ftp->verbose, "Verbose", argc, argv);
}
/* Enable/disable command batching */
static int
dobatch (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
if ((ftp = (struct ftpcli *) p) == NULLFTP)
return -1;
return setbool (&ftp->batch, "Command batching", argc, argv);
}
/* Enable/disable update flag */
static int
doftpupdate (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
if ((ftp = (struct ftpcli *) p) == NULLFTP)
return -1;
return setbool (&ftp->update, "Update with MD5", argc, argv);
}
/* Set verbosity to high (convenience command) */
static int
dohash (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
{
register struct ftpcli *ftp;
if ((ftp = (struct ftpcli *) p) == NULLFTP)
return -1;
tputs ("Hash Printing ");
if (ftp->verbose == V_HASH) {
ftp->verbose = V_HASH + 1;
tputs ("Off\n");
} else {
tputs ("On\n");
ftp->verbose = V_HASH;
}
return 0;
}
/* Close session */
static int
doquit (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
{
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP)
return -1;
usprintf (ftp->control, "QUIT\n");
(void) getresp (ftp, 200); /* Get the closing message */
(void) getresp (ftp, 200); /* Wait for the server to close */
/* prevent spurious retry caused by "error" return */
ftp->state = EXITING_STATE;
return -1;
}
#ifdef LZW
static int
synclzw (register struct ftpcli *ftp)
{
int retval;
usprintf (ftp->control, "XLZW %d %d\n", Lzwbits, Lzwmode);
retval = getresp (ftp, 200);
if (retval >= 200 && retval < 300) {
ftp->lzwbits = Lzwbits;
ftp->lzwmode = Lzwmode;
}
return retval;
}
/* Toggle LZW compressed streams mode on */
static int
doftplzw (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
{
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP)
return -1;
ftp->lzw ^= 1;
tprintf ("200 Client LZW o%s\n", (ftp->lzw) ? "n" : "ff");
return (200);
}
#endif
/* Rename remote file */
static int
doftprename (int argc OPTIONAL, char *argv[], void *p)
{
register struct ftpcli *ftp;
int retval;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP)
return -1;
usprintf (ftp->control, "RNFR %s\n", argv[1]);
retval = getresp (ftp, 350);
if (retval != 350)
return (retval);
usprintf (ftp->control, "RNTO %s\n", argv[2]);
return (getresp (ftp, 200));
}
/* Rename local file */
static int
dolrename (int argc OPTIONAL, char *argv[], void *p)
{
register struct ftpcli *ftp;
char fname1[128];
char fname2[128];
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP)
return -1;
strncpy (fname1, make_fname (ftp->curdirs->dir, argv[1]), 128);
strncpy (fname2, make_fname (ftp->curdirs->dir, argv[2]), 128);
if (rename (fname1, fname2) == -1)
tprintf ("Can't rename: %s\n", SYS_ERRLIST(errno));
else
tprintf ("Local file renamed to '%s'\n", fname2);
return 0;
}
static int
txlate (int argc OPTIONAL, char *argv[], void *p, const char *substr, int parm)
{
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP)
return -1;
usprintf (ftp->control, "%s %s\n", substr, (parm) ? argv[1] : "");
return getresp (ftp, 200);
}
/* Pass PWD to server - included here to allow cmd to be viewed in help list */
static int
dopwd (int argc, char *argv[], void *p)
{
return (txlate (argc, argv, p, "PWD", 0));
}
/* Translate 'cd' to 'cwd' for convenience */
static int
doftpcd (int argc, char *argv[], void *p)
{
if (argc == 1)
return (dopwd (argc, argv, p));
return (txlate (argc, argv, p, "CWD", 1));
}
/* Pass CDUP to server - included here to allow cmd to be viewed in help list */
static int
doftpcdup (int argc, char *argv[], void *p)
{
return (txlate (argc, argv, p, "CDUP", 0));
}
/* Translate 'del' to 'dele' for convenience */
static int
doftpdel (int argc, char *argv[], void *p)
{
return (txlate (argc, argv, p, "DELE", 1));
}
/* Translate 'mkdir' to 'xmkd' for convenience */
static int
domkdir (int argc, char *argv[], void *p)
{
return (txlate (argc, argv, p, "XMKD", 1));
}
/* Translate 'rmdir' to 'xrmd' for convenience */
static int
dormdir (int argc, char *argv[], void *p)
{
return (txlate (argc, argv, p, "XRMD", 1));
}
static int
dobinary (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
{
char *args[2];
char buf[2];
strcpy (buf, "I");
args[1] = buf;
return dotype (2, args, p);
}
static int
doascii (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
{
char *args[2];
char buf[2];
strcpy (buf, "A");
args[1] = buf;
return dotype (2, args, p);
}
/* Handle "type" command from user */
static int
dotype (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP)
return -1;
if (argc < 2) {
switch (ftp->type) {
case IMAGE_TYPE:
tputs ("Image\n");
break;
case ASCII_TYPE:
tputs ("Ascii\n");
break;
case LOGICAL_TYPE:
tprintf ("Logical bytesize %u\n", ftp->logbsize);
break;
default:
break;
}
return 0;
}
switch (*argv[1]) {
case 'i':
case 'I':
case 'b':
case 'B':
ftp->type = IMAGE_TYPE;
break;
case 'a':
case 'A':
ftp->type = ASCII_TYPE;
break;
case 'L':
case 'l':
ftp->type = LOGICAL_TYPE;
ftp->logbsize = atoi (argv[2]);
break;
default:
tprintf ("Invalid type %s\n", argv[1]);
return 1;
}
return 0;
}
/* Handle "ftype" command */
int
doftype (int argc, char *argv[], void *p OPTIONAL)
{
if (argc < 2) {
tputs ("Ftp initial TYPE is ");
switch (Ftp_type) {
case IMAGE_TYPE:
tputs ("Image\n");
break;
case ASCII_TYPE:
tputs ("Ascii\n");
break;
case LOGICAL_TYPE:
tprintf ("Logical bytesize %u\n", Ftp_logbsize);
break;
default:
break;
}
return 0;
}
switch (*argv[1]) {
case 'i':
case 'I':
case 'b':
case 'B':
Ftp_type = IMAGE_TYPE;
break;
case 'a':
case 'A':
Ftp_type = ASCII_TYPE;
break;
case 'L':
case 'l':
if (argc < 3) {
tprintf ("requires a bytesize parameter\nUsage: ftype logical <size>\n");
return 1;
}
Ftp_type = LOGICAL_TYPE;
Ftp_logbsize = atoi (argv[2]);
break;
default:
tprintf ("Invalid type %s\n", argv[1]);
return 1;
}
return 0;
}
/* View added to jnos1.08 by Simon G1FHY _ mod by Paul@wolf.demon.co.uk */
/* Start view transfer. Syntax: view <remote name> */
static int
doftpview (int argc OPTIONAL, char *argv[], void *p)
{
char *remotename;
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
remotename = argv[1];
(void) getsub (ftp, "RETR", remotename, NULLCHAR);
return 0;
}
/* Start receive transfer. Syntax: get <remote name> [<local name>] */
static int
doget (int argc, char *argv[], void *p)
{
char *remotename, *localname;
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
remotename = argv[1];
if (argc < 3)
localname = remotename;
else
localname = argv[2];
if (!ftp->update || compsub (ftp, localname, remotename) != 0)
(void) getsub (ftp, "RETR", remotename, localname);
return 0;
}
/* Get a collection of files */
static int
domget (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
FILE *files, *filel;
char tmpname[80];
char *buf, *local;
#ifdef MSDOS
char *c;
#endif
int i;
#ifdef MSDOS
int inlist;
#endif
long r;
if ((ftp = (struct ftpcli *) p) == NULLFTP) {
tputs (Notsess);
return 1;
}
(void) tmpnam (tmpname);
buf = mallocw (FTPDIRBUF);
ftp->state = RECEIVING_STATE;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '@') {
#ifdef MSDOS
inlist = 1;
#endif
if ((filel = fopen (make_fname (ftp->curdirs->dir, &argv[i][1]), "r")) == NULLFILE) {
tprintf ("Can't open listfile: %s\n", &argv[i][1]);
continue;
}
if ((files = fopen (tmpname, "w")) == NULLFILE) {
tprintf ("Can't open tempfile: %s\n", tmpname);
continue;
}
while (fgets (buf, FTPDIRBUF, filel) != NULLCHAR)
fputs (buf, files);
(void) fclose (files);
(void) fclose (filel);
if ((files = fopen (tmpname, "r")) == NULLFILE) {
tprintf ("Can't open tempfile: %s\n", tmpname);
continue;
}
} else {
#ifdef MSDOS
inlist = 0;
#endif
r = getsub (ftp, "NLST", argv[i], tmpname);
if (ftp->abort)
break; /* Aborted */
if (r == -1 || (files = fopen (tmpname, "r")) == NULLFILE) {
tprintf ("Can't NLST %s\n", argv[i]);
unlink (tmpname);
continue;
}
}
/* The tmp file now contains a list of the remote files, so
* go get 'em. Break out if the user signals an abort.
*/
while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
rip (buf);
local = strdup (buf);
#ifdef MSDOS
if (inlist) {
strrev (local);
(void) strtok (local, "\\/[]<>,?#~()&%");
strrev (local);
}
if ((c = strstr (local, ".")) != NULLCHAR) {
c++;
c = strtok (c, "."); /* remove 2nd period if any*/
}
#endif
if (!ftp->update || compsub (ftp, buf, buf) != 0)
(void) getsub (ftp, "RETR", buf, local);
usflush (ftp->control);
free (local);
if (ftp->abort) {
/* User abort */
ftp->abort = 0;
(void) fclose (files);
unlink (tmpname);
free (buf);
ftp->state = COMMAND_STATE;
return 1;
}
}
(void) fclose (files);
unlink (tmpname);
}
free (buf);
ftp->state = COMMAND_STATE;
ftp->abort = 0;
return 0;
}
/* Resume interrupted file transfer. Syntax: resume <remote name> [<local name>] */
static int
doresume (int argc, char *argv[], void *p)
{
char *remotename, *localname;
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
remotename = argv[1];
if (argc < 3)
localname = remotename;
else
localname = argv[2];
(void) getsub (ftp, "RSME", remotename, localname);
return 0;
}
/* List remote directory. Syntax: dir <remote files> [<local name>] */
static int
dolist (int argc, char *argv[], void *p)
{
char *remotename, *localname;
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
remotename = argv[1];
if (argc > 2)
localname = argv[2];
else
localname = NULLCHAR;
(void) getsub (ftp, "LIST", remotename, localname);
return 0;
}
/* Remote directory list, short form. Syntax: ls <remote files> [<local name>] */
static int
dols (int argc, char *argv[], void *p)
{
char *remotename, *localname;
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
remotename = argv[1];
if (argc > 2)
localname = argv[2];
else
localname = NULLCHAR;
(void) getsub (ftp, "NLST", remotename, localname);
return 0;
}
static int
domd5 (int argc OPTIONAL, char *argv[], void *p)
{
char *remotename;
register struct ftpcli *ftp;
int control;
int resp;
int typewait = 0;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
control = ftp->control;
remotename = argv[1];
if (ftp->typesent != ftp->type) {
switch (ftp->type) {
case ASCII_TYPE:
usprintf (control, "TYPE A\n");
break;
case IMAGE_TYPE:
usprintf (control, "TYPE I\n");
break;
case LOGICAL_TYPE:
usprintf (control, "TYPE L %d\n", ftp->logbsize);
break;
default:
break;
}
ftp->typesent = ftp->type;
if (!ftp->batch) {
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299)
goto failure;
} else
typewait = 1;
}
usprintf (control, "XMD5 %s\n", remotename);
if (typewait)
(void) getresp (ftp, 200);
(void) getresp (ftp, 200);
failure:
return 0;
}
static int
docompare (int argc, char *argv[], void *p)
{
char *remotename, *localname;
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
remotename = argv[1];
if (argc > 2)
localname = argv[2];
else
localname = remotename;
if (compsub (ftp, localname, remotename) == 0)
tputs ("Same\n");
else
tputs ("Different\n");
return 0;
}
/* Compare a collection of files */
static int
domcompare (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
FILE *files;
char *buf;
int i;
long r;
char tmpname[80];
if ((ftp = (struct ftpcli *) p) == NULLFTP) {
tputs (Notsess);
return 1;
}
(void) tmpnam (tmpname);
buf = mallocw (FTPDIRBUF);
ftp->state = RECEIVING_STATE;
for (i = 1; i < argc; i++) {
r = getsub (ftp, "NLST", argv[i], tmpname);
if (ftp->abort)
break; /* Aborted */
if (r == -1 || (files = fopen (tmpname, "r")) == NULLFILE) {
tprintf ("Can't NLST %s\n", argv[i]);
unlink (tmpname);
continue;
}
/* The tmp file now contains a list of the remote files, so
* go get 'em. Break out if the user signals an abort.
*/
while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
rip (buf);
if (compsub (ftp, buf, buf) == 0)
tprintf ("%s - Same\n", buf);
else
tprintf ("%s - Different\n", buf);
if (ftp->abort) {
/* User abort */
ftp->abort = 0;
(void) fclose (files);
unlink (tmpname);
free (buf);
ftp->state = COMMAND_STATE;
return 1;
}
}
(void) fclose (files);
unlink (tmpname);
}
free (buf);
ftp->state = COMMAND_STATE;
ftp->abort = 0;
return 0;
}
/* Common subroutine to compare a local with a remote file
* Return 1 if files are different, 0 if they are the same
*/
static int
compsub (struct ftpcli *ftp, char *localname, char *remotename)
{
char const *mode = NULLCHAR;
char *cp;
FILE *fp;
int control;
int resp, i;
int typewait = 0;
char remhash[16];
char lochash[16];
control = ftp->control;
switch (ftp->type) {
case IMAGE_TYPE:
case LOGICAL_TYPE:
mode = READ_BINARY;
break;
case ASCII_TYPE:
default:
mode = READ_TEXT;
break;
}
if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
tprintf ("Can't read local file %s\n", make_fname (ftp->curdirs->dir, localname));
return 1;
}
if (ftp->typesent != ftp->type) {
switch (ftp->type) {
case ASCII_TYPE:
usprintf (control, "TYPE A\n");
break;
case IMAGE_TYPE:
usprintf (control, "TYPE I\n");
break;
case LOGICAL_TYPE:
usprintf (control, "TYPE L %d\n", ftp->logbsize);
break;
default:
break;
}
ftp->typesent = ftp->type;
if (!ftp->batch) {
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299)
goto failure;
} else
typewait = 1;
}
usprintf (control, "XMD5 %s\n", remotename);
/* Try to overlap the two MD5 operations */
(void) md5hash (fp, lochash, ftp->type == ASCII_TYPE);
(void) fclose (fp);
if (typewait && (resp = getresp (ftp, 200)) > 299)
goto failure;
if ((resp = getresp (ftp, 200)) > 299) {
if (resp == 500)
ftp->update = 0; /* XMD5 not supported */
goto failure;
}
if ((cp = strchr (ftp->line, ' ')) == NULLCHAR) {
tputs ("Error in response\n");
goto failure;
}
/* Convert ascii/hex back to binary */
(void) readhex (remhash, cp, sizeof (remhash));
if (ftp->verbose > 1) {
tputs ("Loc ");
for (i = 0; i < (int) sizeof (lochash); i++)
tprintf ("%02x", lochash[i] & 0xff);
tprintf (" %s\n", make_fname (ftp->curdirs->dir, localname));
}
if (memcmp (lochash, remhash, sizeof (remhash)) == 0)
return 0;
else
return 1;
failure:
return 1;
}
/* Common code to LIST/NLST/RETR/RSME and mget
* Returns number of bytes received if successful
* Returns -1 on error
*/
static long
getsub (register struct ftpcli *ftp, const char *command, const char *remotename, char *localname)
{
unsigned long total;
FILE *fp;
int resp, i, control, savmode;
char const *mode;
struct sockaddr_in lsocket;
struct sockaddr_in lcsocket;
int32 startclk, rate;
int vsave;
int typewait = 0;
int prevstate;
unsigned long starting;
if (ftp == NULLFTP)
return -1;
control = ftp->control;
savmode = ftp->type;
#ifdef __GNUC__
mode = 0; /* semi-spurious warning */
#endif
switch (ftp->type) {
case IMAGE_TYPE:
case LOGICAL_TYPE:
if (strcmp (command, "RSME") == 0)
mode = APPEND_BINARY;
else
mode = WRITE_BINARY;
break;
default:
case ASCII_TYPE:
if (strcmp (command, "RSME") == 0)
mode = APPEND_TEXT;
else
mode = WRITE_TEXT;
break;
}
/* Open the file */
if (localname == NULLCHAR) {
fp = NULLFILE;
} else if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
tprintf ("Can't write %s: %s\n", localname, SYS_ERRLIST(errno));
return -1;
}
/* Open the data connection */
ftp->data = socket (AF_INET, SOCK_STREAM, 0);
(void) listen (ftp->data, 0); /* Accept only one connection */
prevstate = ftp->state;
ftp->state = RECEIVING_STATE;
/* Send TYPE message, if necessary */
if (strcmp (command, "LIST") == 0 || strcmp (command, "NLST") == 0) {
/* Directory listings are always in ASCII */
ftp->type = ASCII_TYPE;
}
if (ftp->typesent != ftp->type) {
switch (ftp->type) {
case ASCII_TYPE:
usprintf (control, "TYPE A\n");
break;
case IMAGE_TYPE:
usprintf (control, "TYPE I\n");
break;
case LOGICAL_TYPE:
usprintf (control, "TYPE L %d\n", ftp->logbsize);
break;
default:
break;
}
ftp->typesent = ftp->type;
if (!ftp->batch) {
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299)
goto failure;
} else
typewait = 1;
}
/* Send the PORT message. Use the IP address
* on the local end of our control connection.
*/
i = SOCKSIZE;
(void) getsockname (ftp->data, (char *) &lsocket, &i); /* Get port number */
if (!i)
goto failure;
i = SOCKSIZE;
(void) getsockname (ftp->control, (char *) &lcsocket, &i);
if (!i)
goto failure;
lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
sendport (control, &lsocket);
if (!ftp->batch) {
/* Get response to PORT command */
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299)
goto failure;
}
#ifdef LZW
if (ftp->lzw && ftp->type == ASCII_TYPE) {
int retval = 200;
retval = synclzw (ftp);
if (retval >= 200 && retval < 300)
lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
}
#endif
/* Generate the command to start the transfer */
if (remotename != NULLCHAR)
usprintf (control, "%s %s\n", command, remotename);
else
usprintf (control, "%s\n", command);
if (ftp->batch) {
/* Get response to TYPE command, if sent */
if (typewait) {
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299)
goto failure;
}
/* Get response to PORT command */
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299)
goto failure;
}
/* Get the intermediate "150" response */
resp = getresp (ftp, 100);
if (resp == -1 || resp >= 400)
goto failure;
/* Wait for the server to open the data connection */
(void) accept (ftp->data, NULLCHAR, (int *) NULL);
startclk = msclock ();
/* If output is to the screen, temporarily disable hash marking */
vsave = ftp->verbose;
if (vsave >= V_HASH && fp == NULLFILE)
ftp->verbose = V_NORMAL;
if (strcmp (command, "RSME") == 0) {
if ((starting = getsize (fp)) == (unsigned long) -1)
starting = 0L;
usprintf (control, "%lu %lu\n", starting, checksum (fp, (long) starting));
usflush (control);
if (fp != NULLFILE)
fseek (fp, (long) starting, SEEK_SET);
}
total = (unsigned long) recvfile (fp, ftp->data, ftp->type, (ftp->verbose >= V_HASH) ? ftp->verbose : 0);
/* Immediately close the data connection; some servers (e.g., TOPS-10)
* wait for the data connection to close completely before returning
* the completion message on the control channel
*/
close_s (ftp->data);
ftp->data = -1;
#ifdef CPM
if (fp != NULLFILE && ftp->type == ASCII_TYPE)
putc (CTLZ, fp);
#endif
if (fp != NULLFILE && fp != stdout)
(void) fclose (fp);
if (remotename == NULLCHAR)
remotename = "";
if (total == (unsigned long) -1) {
tprintf ("%s %s: Error/abort during data transfer\n", command, remotename);
} else if (ftp->verbose >= V_SHORT) {
startclk = msclock () - startclk;
rate = 0;
if (startclk != 0) { /* Avoid divide-by-zero */
if (total < 4294967L)
rate = (long) ((total * 1000) / (uint32) startclk);
else /* Avoid overflow */
rate = (long) (total / (uint32) (startclk / 1000));
}
tprintf ("%s %s: %lu bytes in %lu sec (%lu/sec)\n",
command, remotename, total, startclk / 1000, rate);
}
/* Get the "Sent" message */
(void) getresp (ftp, 200);
ftp->state = (char) prevstate;
ftp->verbose = (int16) vsave;
ftp->type = (char) savmode;
return ((long) total);
failure:
/* Error, quit */
if (fp != NULLFILE && fp != stdout)
(void) fclose (fp);
close_s (ftp->data);
ftp->data = -1;
ftp->state = (char) prevstate;
ftp->type = (char) savmode;
return -1;
}
/* Send a file. Syntax: put <local name> [<remote name>] */
static int
doput (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
char *remotename, *localname;
if ((ftp = (struct ftpcli *) p) == NULLFTP) {
tputs (Notsess);
return 1;
}
localname = argv[1];
if (argc < 3)
remotename = localname;
else
remotename = argv[2];
if (!ftp->update || compsub (ftp, localname, remotename) != 0)
(void) putsub (ftp, remotename, localname, (*argv[0] == 'a') ? 2 : 0);
return 0;
}
/* Put a collection of files */
static int
domput (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
FILE *files;
int i;
#if 0
int j;
#endif
char tmpname[80];
char *buf, *file;
if ((ftp = (struct ftpcli *) p) == NULLFTP) {
tputs (Notsess);
return 1;
}
(void) tmpnam (tmpname);
if ((files = fopen (tmpname, "w+")) == NULLFILE) {
tputs ("Can't list local files\n");
unlink (tmpname);
return 1;
}
for (i = 1; i < argc; i++) {
/* Use the path in the ftp client struct, since user may have done
* a lcd command to change dir !
*/
file = pathname (ftp->curdirs->dir, argv[i]);
#if 0 /* was #ifdef MSDOS */
/* Shift everything back one byte, pathname returns with a leading '/'! */
for (j = 1; j <= strlen (file); j++)
file[j - 1] = file[j];
#endif
(void) getdir (file, 0, files);
free (file);
}
rewind (files);
buf = mallocw (FTPDIRBUF);
ftp->state = SENDING_STATE;
while (fgets (buf, FTPDIRBUF, files) != NULLCHAR) {
rip (buf);
if (!ftp->update || compsub (ftp, buf, buf) != 0)
(void) putsub (ftp, buf, buf, 0);
if (ftp->abort)
break; /* User abort */
usflush (ftp->control);
}
(void) fclose (files);
unlink (tmpname);
free (buf);
ftp->state = COMMAND_STATE;
ftp->abort = 0;
return 0;
}
/* Put a file, appending data to it - iw0cnb */
static int
dorput (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
char *remotename, *localname;
if ((ftp = (struct ftpcli *) p) == NULLFTP) {
tputs (Notsess);
return 1;
}
localname = argv[1];
if (argc < 3)
remotename = localname;
else
remotename = argv[2];
(void) putsub (ftp, remotename, localname, 1);
return 0;
}
/* Common code to put, mput.
* Returns number of bytes sent if successful
* Returns -1 on error
*/
static long
putsub (ftp, remotename, localname, putr)
register struct ftpcli *ftp;
char *remotename, *localname;
int putr; /* Flag: 0 if standard put, 1 if put with resume, if 2 append */
{
char const *mode;
int i, resp, control;
unsigned long total;
FILE *fp;
struct sockaddr_in lsocket, lcsocket;
int32 startclk, rate;
int typewait = 0;
int prevstate;
char *line;
unsigned long starting;
unsigned long check, local_check;
control = ftp->control;
if (ftp->type == IMAGE_TYPE)
mode = READ_BINARY;
else
mode = READ_TEXT;
/* Open the file */
if ((fp = fopen (make_fname (ftp->curdirs->dir, localname), mode)) == NULLFILE) {
tprintf ("Can't read %s: %s\n", localname, SYS_ERRLIST(errno));
return -1;
}
if (ftp->type == ASCII_TYPE && isbinary (fp)) {
tprintf ("Warning: type is ASCII and %s appears to be binary\n", localname);
}
/* Open the data connection */
ftp->data = socket (AF_INET, SOCK_STREAM, 0);
(void) listen (ftp->data, 0);
prevstate = ftp->state;
ftp->state = SENDING_STATE;
/* Send TYPE message, if necessary */
if (ftp->typesent != ftp->type) {
switch (ftp->type) {
case ASCII_TYPE:
usprintf (control, "TYPE A\n");
break;
case IMAGE_TYPE:
usprintf (control, "TYPE I\n");
break;
case LOGICAL_TYPE:
usprintf (control, "TYPE L %d\n", ftp->logbsize);
break;
default:
break;
}
ftp->typesent = ftp->type;
/* Get response to TYPE command */
if (!ftp->batch) {
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299) {
goto failure;
}
} else
typewait = 1;
}
/* Send the PORT message. Use the IP address
* on the local end of our control connection.
*/
i = SOCKSIZE;
(void) getsockname (ftp->data, (char *) &lsocket, &i);
if (!i)
goto failure;
i = SOCKSIZE;
(void) getsockname (ftp->control, (char *) &lcsocket, &i);
if (!i)
goto failure;
lsocket.sin_addr.s_addr = lcsocket.sin_addr.s_addr;
sendport (control, &lsocket);
if (!ftp->batch) {
/* Get response to PORT command */
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299) {
goto failure;
}
}
#ifdef LZW
if (ftp->lzw && ftp->type == ASCII_TYPE) {
int retval = 200;
retval = synclzw (ftp);
if (retval >= 200 && retval < 300)
lzwinit (ftp->data, ftp->lzwbits, ftp->lzwmode);
}
#endif
/* Generate the command to start the transfer */
if (putr == 1)
usprintf (control, "RPUT %s\n", remotename);
else if (putr == 2)
usprintf (control, "APPE %s\n", remotename);
else
usprintf (control, "STOR %s\n", remotename);
if (ftp->batch) {
/* Get response to TYPE command, if sent */
if (typewait) {
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299) {
goto failure;
}
}
/* Get response to PORT command */
resp = getresp (ftp, 200);
if (resp == -1 || resp > 299) {
goto failure;
}
}
/* Get the intermediate "150" response */
resp = getresp (ftp, 100);
if (resp == -1 || resp >= 400) {
goto failure;
}
/* Wait for the data connection to open. Otherwise the first
* block of data would go out with the SYN, and this may confuse
* some other TCPs
*/
(void) accept (ftp->data, NULLCHAR, (int *) NULL);
startclk = msclock ();
if (putr == 1) { /* Wait for file offset and checksum */
char *ctmp;
line = mallocw (40);
if (recvline (control, (unsigned char *) line, 40) == -1) {
free (line);
goto failure;
}
starting = (unsigned long) atol (line);
ctmp = strchr (line, ' ');
if (ctmp != NULLCHAR)
check = (unsigned long) atol (ctmp);
else
check = 0;
free (line);
local_check = checksum (fp, (long) starting);
if (ftp->verbose >= V_HASH)
tprintf ("Remote checksum: %lu - Local checksum: %lu - Offset: %lu\n", check, local_check, starting);
check -= local_check;
if (check != 0) {
tprintf ("Can't send %s: files are different\n", localname);
(void) shutdown (ftp->data, 1);
(void) getresp (ftp, 200);
goto failure;
}
}
total = (unsigned long) sendfile (fp, ftp->data, ftp->type, (ftp->verbose >= V_HASH) ? ftp->verbose : 0);
close_s (ftp->data);
ftp->data = -1;
(void) fclose (fp);
/* Wait for control channel ack before calculating transfer time;
* this accounts for transmitted data in the pipe.
*/
(void) getresp (ftp, 200);
if (total == (unsigned long) -1) {
tprintf ("STOR %s: Error/abort during data transfer\n", remotename);
} else if (ftp->verbose >= V_SHORT) {
startclk = msclock () - startclk;
rate = 0;
if (startclk != 0) { /* Avoid divide-by-zero */
if (total < 4294967L)
rate = (long) ((total * 1000) / (uint32) startclk);
else /* Avoid overflow */
rate = (long) (total / (uint32)(startclk / 1000));
}
tprintf ("STOR %s: %lu bytes in %lu sec (%lu/sec)\n",
remotename, total, startclk / 1000, rate);
}
ftp->state = (char) prevstate;
return ((long) total);
failure:
/* Error, quit */
(void) fclose (fp);
close_s (ftp->data);
ftp->data = -1;
ftp->state = (char) prevstate;
return -1;
}
/* Abort a GET or PUT operation in progress. Note: this will leave
* the partial file on the local or remote system
*/
int
doabort (int argc, char *argv[], void *p)
{
register struct session *sp;
register struct ftpcli *ftp;
sp = (struct session *) p;
if (sp == NULLSESSION)
return -1;
/* Default is the current session, but it can be overridden with
* an argument.
*/
if (argc > 1)
sp = sessptr (argv[1]);
if (sp == NULLSESSION || sp->type != FTP) {
tputs ("Not an active FTP session\n");
return 1;
}
ftp = sp->cb.ftp;
switch (ftp->state) {
case COMMAND_STATE:
tputs ("No active transfer\n");
return 1;
case SENDING_STATE:
/* Send a premature EOF.
* Unfortunately we can't just reset the connection
* since the remote side might end up waiting forever
* for us to send something.
*/
(void) shutdown (ftp->data, 1); /* Note fall-thru */
ftp->abort = 1;
break;
case RECEIVING_STATE:
/* Just blow away the receive socket */
(void) shutdown (ftp->data, 2); /* Note fall-thru */
ftp->abort = 1;
break;
default:
break;
}
return 0;
}
/* send PORT message */
static void
sendport (int s, struct sockaddr_in *thesocket)
{
/* Send PORT a,a,a,a,p,p message */
usprintf (s, "PORT %u,%u,%u,%u,%u,%u\n",
hibyte (hiword (thesocket->sin_addr.s_addr)),
lobyte (hiword (thesocket->sin_addr.s_addr)),
hibyte (loword (thesocket->sin_addr.s_addr)),
lobyte (loword (thesocket->sin_addr.s_addr)),
hibyte (thesocket->sin_port),
lobyte (thesocket->sin_port));
}
/* Wait for, read and display response from FTP server. Return the result code.
*/
static int
getresp (ftp, mincode)
struct ftpcli *ftp;
int mincode; /* Keep reading until at least this code comes back */
{
int rval;
usflush (ftp->control);
for (;;) {
/* Get line */
if (recvline (ftp->control, (unsigned char *) ftp->line, LINELEN) == -1) {
rval = -1;
break;
}
rip (ftp->line);/* Remove cr/lf */
rval = atoi (ftp->line);
if (rval >= 400 || ftp->verbose >= V_NORMAL)
tprintf ("%s\n", ftp->line); /* Display to user */
/* Messages with dashes are continued */
if (ftp->line[3] != '-' && rval >= mincode)
break;
}
return rval;
}
/* Issue a prompt and read a line from the user */
static int
ftpgetline (struct session *sp, const char *prompt, char *buf, int n)
{
/* If there's something already there, don't issue prompt */
if (socklen (sp->input, 0) == 0)
tputs (prompt);
usflush (sp->output);
return recvline (sp->input, (unsigned char *) buf, (unsigned) n);
}
/* Attempt to log in the user whose name is in ftp->username and password
* in pass
*/
static char *
ftpcli_login (struct ftpcli *ftp, char *host)
{
char buf[80], *cp = NULLCHAR, *cp1;
FILE *fp;
if ((fp = fopen (Hostfile, "r")) == NULLFILE)
return NULLCHAR;
while ((void) fgets (buf, sizeof (buf), fp), !feof (fp)) {
buf[strlen (buf) - 1] = '\0'; /* Nuke the newline */
if (buf[0] == '#')
continue; /* Comment */
if ((cp = strchr (buf, ' ')) == NULLCHAR)
/* Bogus entry */
continue;
*cp++ = '\0'; /* Now points to user name */
if (strcmp (host, buf) == 0)
break; /* Found host name */
}
if (feof (fp)) {
/* User name not found in file */
(void) fclose (fp);
return NULLCHAR;
}
(void) fclose (fp);
/* Look for space after user field in file */
cp = skipwhite (cp);
if ((cp1 = strpbrk (cp, " \t")) == NULLCHAR)
/* if not there then we'll prompt */
ftp->password = NULLCHAR;
else
*cp1++ = '\0'; /* Now points to password */
cp1 = skipwhite (cp1);
ftp->password = (strcmp (cp, "*")) ? strdup (cp1) : strdup ("anonymous");
return strdup (cp);
}
int
dolcd (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
if (argc > 1) {
if (!dir_ok (argv[1], ftp->curdirs)) {
tprintf ("Invalid Drive/Directory - %s\n", argv[1]);
return 1;
}
}
tprintf ("Local Directory - %s\n", ftp->curdirs->dir);
return 0;
}
#ifdef ALLSESSIONS
int
doldir (int argc, char *argv[], void *p)
{
register struct ftpcli *ftp;
char **margv;
margv = (char **) callocw (2, sizeof (char *));
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
tputc ('\n');
if (argc == 1)
margv[1] = strdup (ftp->curdirs->dir);
else
margv[1] = strdup (make_dir_path (argc, argv[1], ftp->curdirs->dir));
(void) dodir (2, margv, p);
free (margv[1]);
free (margv);
tputc ('\n');
return 0;
}
#endif
int
dolmkdir (int argc OPTIONAL, char *argv[], void *p)
{
register struct ftpcli *ftp;
char *buf;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
/* undosify(argv[1]); done in make_fname */
buf = strdup (make_fname (ftp->curdirs->dir, argv[1]));
if (mkdir (buf, 0777) == -1)
tprintf ("Can't make %s: %s\n", buf, SYS_ERRLIST(errno));
else
tprintf ("Directory %s Created\n", buf);
free (buf);
return 0;
}
int
dolrmdir (int argc OPTIONAL, char *argv[], void *p)
{
register struct ftpcli *ftp;
char *buf;
ftp = (struct ftpcli *) p;
if (ftp == NULLFTP) {
tputs (Notsess);
return 1;
}
buf = strdup (make_fname (ftp->curdirs->dir, argv[1]));
if (rmdir (buf) == -1)
tprintf ("Can't remove %s: %s\n", buf, SYS_ERRLIST(errno));
else
tprintf ("Directory %s Removed\n", buf);
free (buf);
return 0;
}
#endif